using System;
using System.Text;

namespace BenchmarkWatch.NET
{
    /// <summary>
    /// Provide a cached reusable instance of StringBuilder per thread.
    /// </summary>
    internal static class StringBuilderCached
    {
        // 这个值360是在与性能专家的讨论中选择的，是在每个线程使用尽可能少的内存和仍然覆盖VS设计者启动路径上的大部分短暂的StringBuilder创建之间的折衷。
        internal const int MaxBuilderSize = 360;
        private const int DefaultCapacity = 64;

        [ThreadStatic]
        private static StringBuilder _instance;

        /// <summary>Get a StringBuilder for the specified capacity.</summary>
        /// /// <remarks>If a StringBuilder of an appropriate size is cached, it will be returned and the cache emptied.</remarks>
        public static StringBuilder Rent(string seedstr, int capacity = DefaultCapacity)
        {
            if (capacity <= MaxBuilderSize)
            {
                var sb = _instance;
                if (sb != null)
                {
                    // 当请求的大小大于当前容量时, 通过获取一个新的StringBuilder来避免Stringbuilder块的碎片化
                    if (capacity <= sb.Capacity)
                    {
                        _instance = null;
                        sb.Length = 0;
                        sb.Append(seedstr);
                        return sb;
                    }
                }
            }

            return new StringBuilder(seedstr, capacity);
        }

        /// <summary>Get a StringBuilder for the specified capacity.</summary>
        /// <remarks>If a StringBuilder of an appropriate size is cached, it will be returned and the cache emptied.</remarks>
        public static StringBuilder Rent(int capacity = DefaultCapacity)
        {
            if (capacity <= MaxBuilderSize)
            {
                var sb = _instance;
                if (sb != null)
                {
                    // 当请求的大小大于当前容量时, 通过获取一个新的StringBuilder来避免Stringbuilder块的碎片化
                    if (capacity <= sb.Capacity)
                    {
                        _instance = null;
                        sb.Length = 0;
                        return sb;
                    }
                }
            }

            return new StringBuilder(capacity);
        }

        /// <summary>Place the specified builder in the cache if it is not too big.</summary>
        public static void Return(StringBuilder sb)
        {
            if (sb.Capacity <= MaxBuilderSize)
            {
                _instance = sb;
            }
        }

        /// <summary>ToString() the stringbuilder, Release it to the cache, and return the resulting string.</summary>
        public static string ToStringAndReturn(this StringBuilder sb)
        {
            string result = sb.ToString();
            Return(sb);
            return result;
        }

        /// <summary>ToString() the stringbuilder, Release it to the cache, and return the resulting string.</summary>
        public static string ToStringAndReturn(this StringBuilder sb, int startIndex, int length)
        {
            string result = sb.ToString(startIndex, length);
            Return(sb);
            return result;
        }
    }
}
